package com.gt.utils;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * RSA分段加密工具类
 *
 */
public class TimeRSAUtilSegment {
    private static final String ALGORITHM = "RSA";

    /**
     * 加密算法
     */
    private static final String CIPHER_DE = "RSA";

    /**
     * 解密算法
     */
    private static final String CIPHER_EN = "RSA";

    /**
     * 密钥长度
     */
    private static final Integer KEY_LENGTH = 1024;

    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;

    /**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 128;
    // 密钥长度 1024 bit ；密钥格式：PKCS#8
    // 公钥，用于服务商加密商户数据
    // 邮刊公钥
    static String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCw12em12nl3bQhhEHGeKcHFljc+gGjAxUcze0Bmlw2sE6YGoHpvvNqz1WmkMq+SkdyrsJ3M0keXPBWOcENFVfYV3lv0/xNrR68LA6eU7wVffOZ0kYItg9MmRBJ/9AsjN2LLSWOMwMpu6BpmF/hK3ZX5WJhOAb9UjBg8chWgTxTkQIDAQAB";
    // 国通私钥
    static String privateKey = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALDXZ6bXaeXdtCGEQcZ4pwcWWNz6AaMDFRzN7QGaXDawTpgagem+82rPVaaQyr5KR3KuwnczSR5c8FY5wQ0VV9hXeW/T/E2tHrwsDp5TvBV985nSRgi2D0yZEEn/0CyM3YstJY4zAym7oGmYX+ErdlflYmE4Bv1SMGDxyFaBPFORAgMBAAECgYEAq8bRXHNq3mpZCyWZbtzMAkpmz1/aLypTW8N8MU5rvIPOFFnLT+64LExx+nYzOlyUwoWXSIp8wA2vN1Kqf7b3uASTVyH2lic12ZcWxjjc7WF96pXUXNJD/cN25lewU3jBVeCLwvk0lpdia8UVB7AsGhhcNdO98TAVNfbVqQGKqAECQQDe030eShS2l6SbQBqpzqcfqNfZFpP1r9ewp5FJ7iIAJ80SIC8mA6hs9cupE04BQVfh+QoYeF5EXzjPWCwxAFhxAkEAyytQUmTNgUPFbfbRtjx7a4RgIGfr4sbB4QHQy8v1keLeKALtoNt5eUnyXor7u0hXe/JU0r//+g3vezs6i/49IQJAbrieIk/jTPu7El3fIeOKzcODRd7fNKTkw2XwXtESWgts7gXKB9Sne0UDpwbtqtgCSEoMRy6AgO7j9ru0ccDfMQJBAJK7gZNAQjutmpVEwUkAfZK1VEeTRoXOTpAXI5lMgNsQIqp7EuwuFplGksk9T3l/Uc+uwRxElrceAWva5vnccIECQDU0mONSPuy1iO19Rtuep3S5/OY1Tjnj716wH+GhxXHuK4q09GzRtkmvoPgpyWFhRV4R5WO7jTXqelINv/eo6aI=";
    /**
     * 公钥加密
     *
     * @param data 待加密的数据
     * @param publicKey 公钥
     * @return byte[]
     */
    public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception {
        // 得到公钥
        byte[] keyBytes = Base64.decodeBase64(publicKey.getBytes());
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        Key key = keyFactory.generatePublic(x509EncodedKeySpec);
        // 加密数据，分段加密
        Cipher cipher = Cipher.getInstance(CIPHER_EN);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        int inputLength = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offset = 0;
        byte[] cache;
        int i = 0;
        while (inputLength - offset > 0) {
            if (inputLength - offset > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data, offset, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data, offset, inputLength - offset);
            }
            out.write(cache, 0, cache.length);
            i++;
            offset = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        return encryptedData;
    }

    /**
     * 私钥解密
     *
     * @param data 加密后的数据
     * @param privateKey 私钥
     * @return byte[]
     */
    public static byte[] decryptByPrivateKey(byte[] data, String privateKey) throws Exception {
        // 得到私钥
        byte[] keyBytes = Base64.decodeBase64(privateKey.getBytes());
        PKCS8EncodedKeySpec pKCS8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        Key key = keyFactory.generatePrivate(pKCS8EncodedKeySpec);
        // 解密数据，分段解密
        Cipher cipher = Cipher.getInstance(CIPHER_DE);
        cipher.init(Cipher.DECRYPT_MODE, key);
        int inputLength = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offset = 0;
        byte[] cache;
        int i = 0;
        byte[] tmp;
        while (inputLength - offset > 0) {
            if (inputLength - offset > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(data, offset, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data, offset, inputLength - offset);
            }
//            out.write(cache, 0, cache.length);
            out.write(cache);
            i++;
            offset = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return decryptedData;
    }

    public static void main(String[] args) throws Exception{
        String message = "{\n" +
                "    \"source\":\"8a8296c3ca7f4b0db80e7b0139830751\",\n" +
                "    \"url\":\"https://api.mch.weixin.qq.com/v3/marketing/favor/users/oy7am06VvLYESwNK55Hvq872_04w/coupons\",\n" +
                "    \"method\":\"POST\",\n" +
                "    \"body\":{\t\t\n" +
                "\t     \"stock_id\": \"15900726\",\n" +
                "\t     \"out_request_no\": \"89560002019101000199\",\n" +
                "\t     \"appid\": \"wxf5226ef6096cf937\",\n" +
                "\t     \"stock_creator_mchid\": \"1501970731\"\n" +
                "    }\n" +
                "}";
        //      对返回的参数进行rsa加密
        String encryptStr = new String(Base64.encodeBase64(RSAUtilSegment.encryptByPublicKey(message.getBytes(), publicKey)));
        System.out.println(encryptStr);

        String encodedData = "XZvON9oZl1Pf+PcgQTqocBuu+VSnBMogftN0E6In8nQgAMAUfIudF1MzMDRk7BJW7cGvHFIpoPQTTbGkytdXaaSd+A779lXpBrzhFizOedKS/8cYMOQKX3jzv6Wf9YhzP1fPj5pQRTGiLvvRkM9JxyuM5g48V+ApHjJAZw8IxZybAN6Q+6c54IpeO16al0e6Wlfa9Hf/HuDn0bonq5HyHd7vTR8JcCWfmGDDI5/sgrBWShQylZnnG8NPRoYBhN3xwYJKhO1lukfLiYYq2A2tVydtsu1JfzCmKJaUwb5Ow6Z+yrdEbrZzGF2QynALF73Tn0GfqZWgQq7/OR70AOmDkA==";
//        String str = "dKQyoRGyvpVsIh3MetkC/y/00kGpvx6FPsYbukNpAotEpZA1SgAQZ0+I04H+6wc/L9NI/tdby0disZ9cfgF2BbI8NB58LqCR+fnj0Tr/JgEMoELDiiRKKeBhn+ZfgJRcRg4bBkxhCm2ZlO7WIhBCLikNknccWfCu6uVuMPIh+JOCKn8TrySBRWQUaaYfZouMzDhEKaLPWzEoCItfrC7dNCeOThbd9ERhCEtTWl7RCkNd+juFmk/+2S6UzHYfDe9n9lMs+Q4uwpk1g19kuIh2t2aIMECrEDTqjRX7G+i172/A2BPz8pObyV2AaHSrBcp2bLikH2V993tfx/rfhQVefpuvmbm5Ep6waXpr6UB4T8rYLijy7zu6EzNqu8GPY2nwrw4VNqLbTHO/O8q+MLKsL2zTnt7YZgkVNum9cRtw0mhxm3CVo5dhIPKFytcaC8CORn/6XB08iu0p08TZ/bxVF/PAVT5oVxNukkRFctHU2lAB1kzghVT3I8dLAz9KkLEEjzKDQmbw9v5LL35l30+/hq5VYZqqZWYOmX1BybDTXCXs82JKm0gwMr60wF35MAQakUGpwKPP9pZKLUbt4PdIKlvvBJaZKscnOWe5uCEFDgY3Fe7srdHSniKCynq23QTriKLCAmBLyCl15xzcICPXPyeW7Ea+jEgHO0Y7mj00VTQNP4tivuSyuMu9ggRbzUKX8UaZK0YmpdH/vXsNeShBhqISHh61GWFRdKfI3RAfizjDMvKJOBGWCa8vdFTXxWGU+Cho0Rm6s0KQ7H2RIbDiRxy8rz94Ld3otzFTTtClXUPjaECBaRQcFQwbvu2p43WfRaVW/VuW7sp/tuBun402MQ==";
//        RSAUtilSegment.decryptByPrivateKey(Base64.decodeBase64(encodedData), privateKey);
        byte[] decryptStrByte = TimeRSAUtilSegment.decryptByPrivateKey(Base64.decodeBase64(encodedData), privateKey);
        System.out.println(new String(decryptStrByte));
    }
}
